﻿using System.Collections.ObjectModel;
using ManoMachine.Common;
using ManoMachine.Emulator;

namespace ManoMachine.IDE.ViewModel
{
    #region

    using System;
    using System.Windows.Forms;

    using GalaSoft.MvvmLight.Command;

    using ManoMachine.Emulator.Emulator;

    using Telerik.Windows.Controls;

    using ViewModelBase = GalaSoft.MvvmLight.ViewModelBase;

    #endregion

    public class ShellViewModel : ViewModelBase
    {
        #region Constants and Fields

        public RelayCommand BuildCommand { get; set; }

        public RelayCommand EmulateCommand { get; set; }

        public RelayCommand LoadCommand { get; set; }

        public RelayCommand NewProjectCommand { get; set; }

        public RelayCommand SaveCommand { get; set; }

        public RelayCommand StepForwardCommand { get; set; }

        #endregion

        #region Constructors and Destructors

        public ShellViewModel()
        {
            InitMe();
        }

        private void InitMe()
        {
            this.CurrentAssembler = new Assembler.Assembler();
            Errors = new ObservableCollection<Tuple<int, string>>();
            SymbolsTable = new ObservableCollection<Tuple<string, string>>();
            MemoryMap = new ObservableCollection<Tuple<string, string, string>>();
            this.CurrentEmulator = new Emulator();
        }

        #endregion

        public ObservableCollection<Tuple<int, string>> Errors { get; private set; }

        public ObservableCollection<Tuple<string, string>> SymbolsTable { get; private set; }

        public ObservableCollection<Tuple<string, string, string>> MemoryMap { get; private set; }

        public bool IsParallel { get; set; }

        private bool isInEmulationMode;

        public bool IsInEmulationMode
        {
            get
            {
                return this.isInEmulationMode;
            }
            set
            {
                this.isInEmulationMode = value;
                this.RaisePropertyChanged("IsInEmulationMode");
            }
        }


        private MemoryItem _startMemoryItem;
        public MemoryItem StartMemoryItem
        {
            get { return _startMemoryItem; }
            set { _startMemoryItem = value;
            this.RaisePropertyChanged("StartMemoryItem");
            }
        }

        private Emulator currentEmulator;

        public Emulator CurrentEmulator
        {
            get
            {
                return this.currentEmulator;
            }
            set
            {
                this.currentEmulator = value;
                this.RaisePropertyChanged("CurrentEmulator");
            }
        }

        private Assembler.Assembler currentAssembler;

        public Assembler.Assembler CurrentAssembler
        {
            get
            {
                return this.currentAssembler;
            }
            set
            {
                this.currentAssembler = value;
                this.RaisePropertyChanged("CurrentAssembler");
            }
        }

        #region Methods

        public RichTextBox SourceCodeContainer
        {
            get;
            set;
        }

        public void BuildCommandExecute()
        {
            this.IsInEmulationMode = false;
            Build();
        }

        private void Build()
        {
            this.Errors.Clear();
            this.SymbolsTable.Clear();
            this.MemoryMap.Clear();

            ///////////////////////////////////////////////////////////////////////////////////

            if (string.IsNullOrWhiteSpace(this.SourceCodeContainer.Text))
            {
                RadWindow.Alert("Please Enter valid source Code");
                return;
            }

            this.CurrentAssembler.Restart();
            AssemblerResult assemblerResult = this.CurrentAssembler.Assemble(this.SourceCodeContainer.Text, IsParallel);

            if (assemblerResult.Errors != null && assemblerResult.Errors.Count > 0)
            {
                RadWindow.Alert(string.Format("Faild, {0} Error(s)", assemblerResult.Errors.Count));

                foreach (var error in assemblerResult.Errors)
                {
                    this.Errors.Add(error);
                }
                return;
            }

            if (isInEmulationMode)
            {
                foreach (var tt in assemblerResult.SymbolsTable
)
                {
                    this.SymbolsTable.Add(new Tuple<string, string>(tt.Item1, tt.Item2.ToString("X")));
                }

              this.StartMemoryItem =  this.CurrentEmulator.Run(startAddress: assemblerResult.StartAddress, memoryMap: assemblerResult.MemoryMap);
            }
            else
            {
                foreach (var tt in assemblerResult.SymbolsTable
)
                {
                    this.SymbolsTable.Add(new Tuple<string, string>(tt.Item1, tt.Item2.ToString("X")));
                }
                MessageBox.Show("Successful");
            }
        }

        public void EmulateCommandExecute()
        {
            this.IsInEmulationMode = true;
            this.Build();
        }

        public void LoadCommandExecute()
        {
            throw new NotImplementedException();
        }

        public void NewCommandExecute()
        {
            throw new NotImplementedException();
        }

        public void SaveCommandExecute()
        {
            throw new NotImplementedException();
        }

        public void StepForwardExecute()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}